Caches referenced by the annotations can be configured, either in an ehcache.xml
(usually kept in the grails-app/conf
directory) file, using EhCacheFactoryBean
definitions in grails-app/conf/spring/resources.groovy
or via Config.groovy
. If you do not configure caches individually they will be created on demand using defaults.Configuring caches with resources.groovy
You can configure caches in grails-app/conf/spring/resources.groovy
using instances of Spring's EhCacheFactoryBean class. For example:grails-app/conf/spring/resources.groovy
pirateCache(EhCacheFactoryBean) { bean ->
cacheManager = ref("springcacheCacheManager")
cacheName = "pirateCache"
// these are just examples of properties you could set
eternal = false
diskPersistent = false
memoryStoreEvictionPolicy = "LRU"
}
You can inherit default cache properties from those defined in Config.groovy
by setting the factory bean's parent to 'springcacheDefaultCache
'. For example:pirateCache(EhCacheFactoryBean) { bean ->
bean.parent = ref("springcacheDefaultCache")
cacheName = "pirateCache"
// set any properties unique to this cache
memoryStoreEvictionPolicy = "LRU"
}
Configuring caches with Config.groovy
The Springcache plugin enables you to define caches in Config.groovy
for convenience. For example:grails-app/conf/Config.groovy
springcache {
defaults {
// set default cache properties that will apply to all caches that do not override them
eternal = false
diskPersistent = false
}
caches {
pirateCache {
// set any properties unique to this cache
memoryStoreEvictionPolicy = "LRU"
}
}
}
Under the hood this is simply setting up EhCacheFactoryBean
instances in the Spring context, so it is up to you whether you prefer to use resources.groovy
or Config.groovy
there is not much difference.The properties shown are just examples, see the EhCacheFactoryBean documentation for full details of all the properties you can set.
Flushing content caches with service methods and vice-versa
There is nothing special about the different types of cache so it's perfectly fine to flush a content cache with a @CacheFlush
annotation on a service method or a service method cache with a @CacheFlush
annotation on a controller action. There's also no reason that you shouldn't use the same cache for both service method and content caching the keys will be quite distinct so this will not be a problem.Tearing down caches in tests
In integration test and some types of functional test (e.g. Selenium RC tests when not running in remote mode) your tests can have Spring beans automatically injected. You can use this facility to tear down caches between tests. For example:def springcacheService // auto-injected service bean from pluginvoid tearDown() {
super.tearDown()
springcacheService.flushAll()
// only need to do this if your tests are making assertions about hit/miss counts, etc.
springcacheService.clearStatistics()
}
Disabling
Rather than tearing down caches between tests you may prefer to disable the plugin altogether. This is done by setting the config key springcache.enabled = false
which can be done on a per-environment basis. For example:springcache {
// cache definitions, etc
}environments {
development {
springcache.enabled = false
}
}
Whilst this makes things simpler I would encourage you to run end-to-end tests and continuous integration in as 'production-like' an environment as possible. If your continuous integration build is running with the plugin enabled you are much less likely to get any surprising behaviour when you release your app to a production environment.Logging
To see logging from the plugin set the logging level on grails.plugin.springcache
in your Config.groovy
file.Response headers
The plugin sets a header X-Springcache-Cached with a value of true or false to indicate whether or not a controller response was served from the cache. This only applies to the "main" request and not to any content included using the g:include
tag.
Can I evict only some of the contents of a cache instead of flushing the whole thing?
No. It's not possible to 'reverse engineer' cache keys into the values that were used to generate them so how would you know which keys to evict? If you find yourself asking this question you should consider using more focused caches rather than putting everything into the same bucket. The pursuit of 100% efficiency where no service method or controller action is ever invoked when its contents could conceivably have been served from a cache is subject to the law of diminishing returns. Any time you flush a cache you may well discard some entries that could potentially still have been used but so long as your caches are set up sensibly that's really not something that you should worry about.My cache config doesn't seem to be working.
Ensure all your config for the Springcache plugin is nested inside a single springcache
block in Config.groovy
otherwise only the last block will take effect.Can I programatically disable caching in specific circumstances such as when a user is logged in?
In the case of controller caching you can do so by setting a Cache-Control response header with a value of "no-cache" which can be done manually, or by using the command cache false
provided by the Cache Headers plugin. See Cache HeadersWhy isn't there a taglib so I can just wrap parts of my page that need caching?
It's something I may add but from a purist point of view I'm not very keen on the idea. Caching is a separate concern from view rendering and the two really shouldn't be mixed up. So far the plugin has deliberately taken a declarative approach to caching which encourages you to maintain a good separation of concerns.If this is something you really want to see, vote for the issue on JIRA here: "GRAILSPLUGINS-2564":http://jira.codehaus.org/browse/GRAILSPLUGINS-2564Successive versions of the plugin have introduced some non-backwards compatible changes. If you are upgrading from an earlier version you will need to consider the following:Upgrading from 1.2.* to 1.3:
- You can no longer inject keyGenerator into the springcacheFilter bean. Instead you can override the springcacheDefaultKeyGenerator bean or specify the keyGenerator element on individual
@Cacheable
annotations. See Content Cache Keys
Upgrading from 1.1.* to 1.2:
- The plugin no longer uses caching and flushing models. Instead cache names are referenced directly by the annotations. This means you will need to 'inline' your model definitions from
Config.groovy
to your annotations.
- The plugin no longer supports alternate cache libraries, it's EhCache or nothing.
From pre 1.1:
- You will need to change the import statements for your
@Cacheable
and @CacheFlush
annotations to point to the grails.plugin.springcache.annotations
package.